﻿using BoldBrick.SharePoint.CommonControls.ListItemProcessing;
using BoldBrick.SharePoint.CommonControls.Utils;
using Microsoft.SharePoint;

namespace BoldBrick.SharePoint.CommonControls.Extensions
{
	/// <summary>
	/// Extension class for <see cref="SPListItem"/> objects
	/// </summary>
	public static class SPListItemEx
	{
		#region ------ Get Value ------------------------------------------------------------------

		/// <summary>
		/// Gets typed value of field of item
		/// </summary>
		/// <typeparam name="TClass">Type of the value</typeparam>
		/// <param name="item">The list item</param>
		/// <param name="fieldName">Name of the field</param>
		/// <returns>Returns typed value of the field of the item</returns>
		public static TClass GetValueObject<TClass>(this SPListItem item, string fieldName) where TClass : class
		{
			object obj = item[fieldName];

			if (obj == null)
				return null;

			if (obj is TClass)
				return (TClass) obj;
			
			SPField field = item.ParentList.Fields.GetField(fieldName);
			TClass objectTyped = field.GetFieldValue(obj.ToString()) as TClass;
			return objectTyped;
		}
		
		/// <summary>
		/// Gets typed value of field of item
		/// </summary>
		/// <typeparam name="TClass">Type of the value</typeparam>
		/// <param name="item">The list item</param>
		/// <param name="fieldName">Name of the field</param>
		/// <returns>Returns typed value of the field of the item</returns>
		public static TClass? GetValue<TClass>(this SPListItem item, string fieldName) where TClass : struct
		{
			object obj = item[fieldName];

			if (obj == null)
				return null;

			if (obj is TClass)
				return (TClass) obj;

			return null;
		}

		#endregion

		#region ------ Update Methods -------------------------------------------------------------

		/// <summary>
		/// Calls Update method, events couls be suppressed
		/// </summary>
		/// <param name="item">Item to update</param>
		/// <param name="fireEvents">True for firing events, otherwise false</param>
		public static void Update(this SPListItem item, bool fireEvents)
		{
			if (fireEvents)
			{
				item.Update();
			}
			else
			{
				using (new EventsHelper.NoEvents())
				{
					item.Update();
				}
			}
		}

		/// <summary>
		/// Calls SystemUpdate method without firing any even
		/// </summary>
		/// <param name="item">Item to update</param>
		public static void SystemUpdateWithNoEvents(this SPListItem item)
		{
			using (new EventsHelper.NoEvents())
			{
				item.SystemUpdate(false);
			}
		}

		#endregion

		#region ------ Copy & Move Methods --------------------------------------------------------

		public static int Copy(this SPListItem itemSource, SPList listDest, SPFolder folderDest, string fileNameDest, bool overwrite)
		{
			return CopyMoveItem(itemSource, listDest, folderDest, fileNameDest, overwrite, OperationType.Copy);
		}

		public static int Move(this SPListItem itemSource, SPList listDest, SPFolder folderDest, string fileNameDest, bool overwrite)
		{
			return CopyMoveItem(itemSource, listDest, folderDest, fileNameDest, overwrite, OperationType.Move);
		}

		private static int CopyMoveItem(this SPListItem itemSource, SPList listDest, SPFolder folderDest, string fileNameDest, bool overwrite, OperationType operationType)
		{
			if (!folderDest.Exists)
			{
				throw new CopyItemException("MoveItem_Error_DestinationFolderDoesNotExist", null);
			}

			ListItemCopyOptions options =
				new ListItemCopyOptions
					{
						IncludeAttachments = true,
						OperationType = operationType,
						Overwrite = overwrite,
						DestinationFolder = folderDest,
						DestinationFileName = fileNameDest
					};

			using (ListItemCopier myCopier = new ListItemCopier(itemSource, listDest, options))
			{
				int itemDestinationID = myCopier.Copy();
				return itemDestinationID;
			}
		}

		public static void CopyValuesTo(this SPListItem itemSource, SPListItem itemDest)
		{
			ListItemCopier.CopyFieldValues(itemSource, itemDest);
			itemDest.SystemUpdateWithNoEvents();
		}

		#endregion

		
	}
}
